﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using Twodi.Aspect.Interfaces;
using Twodi.Behavior;
using Microsoft.Xna.Framework;

namespace Twodi.Structs
{
    public class Animation : AbstractBehavior<ITextureAspect>
    {
        protected String name;

        protected int frameIndex = -1;

        protected BindingList<AnimationFrame> frames;

        protected RegressiveTimer frameTimer;

        public bool Repeat
        {
            get;
            set;
        }

        public Animation(String name, ITextureAspect component, params AnimationFrame[] frames)
            : this(name, component)
        {
            for (int i = 0; i < frames.Length; i++)
            {
                Frames.Add(frames[i]);
            }
        }

        public Animation(String name, ITextureAspect component)
            : base(component)
        {
            Name = name;

            Frames = new BindingList<AnimationFrame>();

            FrameTimer = new RegressiveTimer();

            Frames.ListChanged += (sender, e) =>
            {
                if (Frames.Count == 1)
                {
                    FrameIndex = 0;
                }
            };

            frameTimer.Finished += (sender, e) =>
            {
                if (Repeat)
                {
                    FrameIndex = (FrameIndex + 1) % Frames.Count;
                    SetFrameConfiguration();
                }
                else
                {
                    if (FrameIndex != frames.Count - 1)
                    {
                        FrameIndex = (FrameIndex + 1) % Frames.Count;
                        SetFrameConfiguration();
                    }
                    else
                    {
                        onFinished(EventArgs.Empty);
                    }
                }                
            };
        }

        private void SetFrameConfiguration()
        {
            this.FrameTimer.Countdown = Frame.Time;
            this.FrameTimer.Reset();
            this.Component.TextureProperties.Source = Frame.Source;
        }

        public void Reset()
        {
            this.FrameIndex = 0;
            this.SetFrameConfiguration();
        }

        public override void Initialize()
        {
            return;
        }

        public override void Update(GameTime gameTime)
        {
            if (!Enabled) return;
            FrameTimer.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            return;
        }

        public override bool Handle(Input.KeyboardInput input)
        {
            throw new NotImplementedException();
        }

        public override bool Handle(Input.MouseInput input)
        {
            throw new NotImplementedException();
        }

        public virtual void Add(params AnimationFrame[] frames)
        {
            for (int i = 0; i < frames.Length; i++)
            {
                this.Frames.Add(frames[i]);
            }
        }

        public AnimationFrame Frame
        {
            get
            {
                return Frames[FrameIndex];
            }
        }

        public BindingList<AnimationFrame> Frames
        {
            get { return this.frames; }
            set
            {
                this.frames = value;
                onFramesChanged(EventArgs.Empty);
            }
        }

        public int FrameIndex
        {
            get { return this.frameIndex; }
            set
            {
                this.frameIndex = value;
                onFrameIndexChanged(EventArgs.Empty);
            }
        }
        public String Name
        {
            get { return this.name; }
            set
            {
                this.name = value;
                onNameChanged(EventArgs.Empty);
            }
        }

        public RegressiveTimer FrameTimer
        {
            get { return this.frameTimer; }
            set
            {
                this.frameTimer = value;
                onFrameTimerChanged(EventArgs.Empty);
            }
        }

        public event EventHandler<EventArgs> FramesChanged;

        public event EventHandler<EventArgs> FrameIndexChanged;

        public event EventHandler<EventArgs> NameChanged;

        public event EventHandler<EventArgs> FrameTimerChanged;

        public event EventHandler<EventArgs> Finished;

        protected virtual void onFramesChanged(EventArgs e)
        {
            if (FramesChanged != null)
            {
                FramesChanged(this, e);
            }
        }

        protected virtual void onFrameIndexChanged(EventArgs e)
        {
            if (FrameIndexChanged != null)
            {
                FrameIndexChanged(this, e);
            }
        }

        protected virtual void onNameChanged(EventArgs e)
        {
            if (NameChanged != null)
            {
                NameChanged(this, e);
            }
        }

        protected virtual void onFrameTimerChanged(EventArgs e)
        {
            if (FrameTimerChanged != null)
            {
                FrameTimerChanged(this, e);
            }
        }

        protected virtual void onFinished(EventArgs e)
        {
            if (Finished != null)
            {
                Finished(this, e);
            }
        }
    }
}
